/*
 * @componentName:
 * @待处理问题:
 * @已处理问题:
 * @Author: 舒克
 * @Official Accounts: 氧化1028
 * @email: 143587623@qq.com
 * @github: https://gitee.com/KingSio
 * @Date: 2021-03-29 19:51:59
 * @LastEditTime: 2021-03-29 21:02:54
 * @FilePath: \源码记录\Vue3\开始\1.vue2.0简单实现原理-数组.js
 */
/* 
1.响应式原理
2.数据变化》视图更新

*/

//1.先初始化一个对象

let data = {
  name: "小明",
  age: [1,2,3],
};
observer(data); //观察数据是否变化
//2.重新赋值改变数据
//a:单层数据
// data.name="小红"
// console.log("更新数据成功："+data.name);

//b:多层数据，改变value值的
//data.age.n="200岁"
//console.log("更新数据成功："+data.age.n);

//c:多层数据，改变整个对象的
data.age.push(4);//需要对数据的方法进行重写，push、join shift unshift pop reverse sort
console.log("更新数据成功：" + data.age);
//2.观察数据是否变化，，，tag是要重新改变的值，但是要判断是否是对象


//如果需要重写，需要拿到原型的数组方法
let oldArrayPrototype=Array.prototype;
//创建一个新的数组原型，不会覆盖原来的，继承
var  proto=Object.create(oldArrayPrototype)
let ArrayMethods=['push','shift','unshift']
//对数组方法重写
ArrayMethods.forEach(methods=>{

    proto[methods]=function(){//函数劫持，把函数重写，内部继续使用原有的数组方法
        oldArrayPrototype[methods].call(this,...arguments)
        console.log("更新视图成功");
    }
})

//4.更新视图
function updateView() {
    console.log("更新视图成功");
  }
  
function observer(tag) {
  if (typeof tag !== "object" || tag == null) {
    return tag;
  }
  //数组执行
  if(Array.isArray(tag)){
   // Object.setPrototypeOf(tag,proto);// 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性）到另一个对象或
     tag._proto_=proto;
  }
  for (let key in tag) {
    //key》name
    //console.log("data的对象:" + tag);
   // console.log("key>name:" + key);
    console.log("值:" + tag[key]);
    defineReactive(tag, key, tag[key]); //重新定义属性和值
  }
}
//3.使用Object.defineProperty.重新定义数据，给数据增加getter和setter

function defineReactive(tag, key, val) {
  observer(val); //如果数据多层需要再次观察，所以vue2也有一个缺陷，如果数据多层，就好多层递归
  Object.defineProperty(tag, key, {
    get() {
      //如果数据不更新直接返回原来的值
      console.log("取得数据：" + val);

      return val;
    },
    set(newVal) {

      if (newVal !== val) {
      
        //新的数据不等于旧值，表示已更新
        observer(newVal);
         //更新视图
        console.log("更新视图成功");
        val = newVal;
      }
    },
  });
}
